<?php
/**
 * MachForm
 * 
 * © 2007–2025 Appnitro Software. All rights reserved.
 * 
 * This source code is proprietary and may not be copied, modified,
 * or distributed in any form without express written permission from Appnitro Software.
 * 
 * License information: https://www.machform.com/license-agreement/
 */

	require('config.php');
	require('lib/db-session-handler.php');
	require('includes/init-form.php');
	require('includes/db-core.php');
	require('includes/language.php');

	require('includes/helper-functions.php');
	require('includes/filter-functions.php');
	require('includes/post-functions.php');
	require('includes/entry-functions.php');
	require('lib/dompdf/autoload.inc.php');
	require('lib/google-api-client/vendor/autoload.php');
	require('lib/phpmailer/vendor/autoload.php');
	require('lib/HttpClient.class.php');
	require('lib/stripe/init.php');

	$payment_result_status = null;
	class PaymentProcessingException extends Exception {}
	
	try{
		$form_id 			= (int) trim($_GET['form_id'] ?? '0');
		$payment_record_id 	= (int) trim($_GET['record_id'] ?? '0');
		
		$payment_intent_id 			  = trim($_GET['payment_intent'] ?? '');
		$payment_intent_client_secret = trim($_GET['payment_intent_client_secret'] ?? '');

		$setup_intent_id 			  = trim($_GET['setup_intent'] ?? '');
		$setup_intent_client_secret	  = trim($_GET['setup_intent_client_secret'] ?? '');

		$mfsid = trim($_GET['mfsid'] ?? '');
		if(!empty($mfsid)){
			$mfsid = htmlspecialchars(strip_tags($mfsid));
		}

		$dbh = mf_connect_db();
		$mf_settings = mf_get_settings($dbh);
		
		//get form properties data
		$query 	= "select 		
						payment_enable_merchant,
						payment_merchant_type,
						payment_currency,
						payment_ask_billing,
						payment_ask_shipping,
						payment_stripe_live_secret_key,
						payment_stripe_test_secret_key,
						payment_stripe_enable_test_mode,
						payment_enable_recurring,
						logic_success_enable,
						form_redirect_enable,
						form_redirect  
					from 
						".MF_TABLE_PREFIX."forms 
				where 
						form_id=? and form_active=1";
		$params = array($form_id);
			
		$sth = mf_do_query($query,$params,$dbh);
		$row = mf_do_fetch_result($sth);
		
		if(!empty($row)){	
			$payment_enable_merchant 	= (int) $row['payment_enable_merchant'];
			$payment_merchant_type		= $row['payment_merchant_type'];
			$payment_currency 	   		= strtolower($row['payment_currency']);
			$payment_ask_billing 	 	= (int) $row['payment_ask_billing'];
			$payment_ask_shipping 	 	= (int) $row['payment_ask_shipping'];
			$payment_enable_recurring 	= (int) $row['payment_enable_recurring'];	
			$logic_success_enable 	 	= (int) $row['logic_success_enable'];	
			$form_redirect_enable 	 	= (int) $row['form_redirect_enable'];
			$form_redirect 	   		 	= trim($row['form_redirect']);
			$payment_stripe_enable_test_mode 	= (int) $row['payment_stripe_enable_test_mode'];
			$payment_stripe_live_secret_key	 	= trim($row['payment_stripe_live_secret_key']);
			$payment_stripe_test_secret_key	 	= trim($row['payment_stripe_test_secret_key']);
		}

		//default values
		$payment_amount = 0;
		$payment_fullname = null;
		$billing_street = null;
		$billing_city = null;
		$billing_state = null;
		$billing_zipcode = null;
		$billing_country = null;


		//initialize Stripe
		if(!empty($payment_stripe_enable_test_mode)){
			$stripe_secret_key = $payment_stripe_test_secret_key;
		}else{
			$stripe_secret_key = $payment_stripe_live_secret_key;
		}

		$stripe = new \Stripe\StripeClient([
			'api_key' => $stripe_secret_key
		]);

		//validate the request, make sure form payment access exist
		if(empty($_SESSION['mf_form_payment_access'][$form_id])){
			throw new Exception("Your session has expired. Please start the form again.");
		}

		//validate the request, make sure stripe is really enabled for this form
		if(empty($payment_enable_merchant) || $payment_merchant_type != 'stripe'){
			throw new Exception("Stripe is not enabled for this form.");
		}

		if(empty($payment_intent_id) && empty($setup_intent_id)){
			throw new Exception("No payment intent or setup intent id provided.");
		}

		//check ap_form_payments table, make sure there is no record for this entry id yet
		$query = "SELECT COUNT(*) as total FROM `".MF_TABLE_PREFIX."form_payments` WHERE form_id = ? AND record_id = ? AND payment_id IS NOT NULL";
		$params = array($form_id,$payment_record_id);
		$sth = mf_do_query($query,$params,$dbh);
		$row = mf_do_fetch_result($sth);
		if($row['total'] > 0){
			throw new Exception("Payment record already exists for this entry id.");
		}

		//validate the payment intent id and client secret, if there is payment intent
		if(!empty($payment_intent_id) && !empty($payment_intent_client_secret)){
			$payment_intent = $stripe->paymentIntents->retrieve($payment_intent_id);
			if($payment_intent->client_secret != $payment_intent_client_secret){
				throw new Exception("Invalid payment intent client secret.");
			}

			//check if the provided form_id and payment record id is correct
			if($payment_intent->metadata['Form ID'] != $form_id || $payment_intent->metadata['Entry Number'] != $payment_record_id){
				throw new Exception("Invalid form id or payment record id.");
			}

			//check if the payment intent status is succeeded
			if($payment_intent->status == 'processing'){
				throw new PaymentProcessingException("Bank transfer currently processing");
			}else if($payment_intent->status != 'succeeded'){
				throw new Exception("Payment intent status is not succeeded.");
			}

			//if there is billing name, update the customer name
			if(!empty($payment_intent->payment_method)){
				$paymentMethod = $stripe->paymentMethods->retrieve($payment_intent->payment_method);
				if(!empty($paymentMethod->billing_details->name)){
					$payment_fullname = $paymentMethod->billing_details->name;
					$stripe->customers->update($payment_intent->customer, [
						'name' => $payment_fullname
					]);
				}
			}

			$payment_amount = $payment_intent->amount_received / 100; //convert to dollar amount
			$payment_id = $payment_intent->id;
			$payment_currency = $payment_intent->currency;
		}

		//validate the setup intent id and client secret, if there is setup intent
		if(!empty($setup_intent_id) && !empty($setup_intent_client_secret)){
			$setup_intent = $stripe->setupIntents->retrieve($setup_intent_id);
			if($setup_intent->client_secret != $setup_intent_client_secret){
				throw new Exception("Invalid setup intent client secret.");
			}

			//check if the provided form_id and payment record id is correct
			if($setup_intent->metadata['Form ID'] != $form_id || $setup_intent->metadata['Entry Number'] != $payment_record_id){
				throw new Exception("Invalid form id or payment record id.");
			}

			//check if the setup intent status is succeeded
			if($setup_intent->status == 'processing'){
				throw new PaymentProcessingException("Bank transfer currently processing");
			}else if($setup_intent->status != 'succeeded'){
				throw new Exception("Setup intent status is not succeeded.");
			}

			//if there is billing name, update the customer name
			if(!empty($setup_intent->payment_method)){
				$paymentMethod = $stripe->paymentMethods->retrieve($setup_intent->payment_method);
				if(!empty($paymentMethod->billing_details->name)){
					$payment_fullname = $paymentMethod->billing_details->name;
					$stripe->customers->update($setup_intent->customer, [
						'name' => $payment_fullname
					]);
				}
			}

			$payment_amount = 0; //setup intent does not have amount, so set it to 0
			$payment_id = $setup_intent->id;

		}

		//reaching this point means the payment intent or setup intent is valid and succeeded
		$_SESSION['mf_payment_completed'][$form_id] = true;

		//revoke access to form payment page
		unset($_SESSION['mf_form_payment_access'][$form_id]);
		unset($_SESSION['mf_payment_failed_attempts_counter'][$form_id]);

		//make sure to delete empty record from ap_form_payments table related with current entry_id
		//empty record is possible when the user manually changed the payment status previously
		$query = "DELETE FROM `".MF_TABLE_PREFIX."form_payments` WHERE form_id = ? AND record_id = ? and payment_id IS NULL";
		$params = array($form_id,$payment_record_id);
		mf_do_query($query,$params,$dbh);

		//get billing details, if any
		if(!empty($paymentMethod->billing_details->address)){
			$billing_street = $paymentMethod->billing_details->address->line1."\n".$paymentMethod->billing_details->address->line2;
			$billing_city = $paymentMethod->billing_details->address->city;
			$billing_state = $paymentMethod->billing_details->address->state;
			$billing_zipcode = $paymentMethod->billing_details->address->postal_code;
			$billing_country = $paymentMethod->billing_details->address->country;
		}

		//get shipping details, if any
		if(!empty($payment_intent->shipping)){
			$shipping_street = $payment_intent->shipping->address->line1."\n".$payment_intent->shipping->address->line2;
			$shipping_city = $payment_intent->shipping->address->city;
			$shipping_state = $payment_intent->shipping->address->state;
			$shipping_zipcode = $payment_intent->shipping->address->postal_code;
			$shipping_country = $payment_intent->shipping->address->country;
		}else if(!empty($setup_intent->shipping)){
			$shipping_street = $setup_intent->shipping->address->line1."\n".$setup_intent->shipping->address->line2;
			$shipping_city = $setup_intent->shipping->address->city;
			$shipping_state = $setup_intent->shipping->address->state;
			$shipping_zipcode = $setup_intent->shipping->address->postal_code;
			$shipping_country = $setup_intent->shipping->address->country;
		}
		
		//insert into ap_form_payments table
		$query = "INSERT INTO `".MF_TABLE_PREFIX."form_payments`(
								`form_id`, 
								`record_id`, 
								`payment_id`, 
								`date_created`, 
								`payment_date`, 
								`payment_status`, 
								`payment_fullname`, 
								`payment_amount`, 
								`payment_currency`, 
								`payment_test_mode`,
								`payment_merchant_type`, 
								`status`, 
								`billing_street`, 
								`billing_city`, 
								`billing_state`, 
								`billing_zipcode`, 
								`billing_country`, 
								`same_shipping_address`, 
								`shipping_street`, 
								`shipping_city`, 
								`shipping_state`, 
								`shipping_zipcode`, 
								`shipping_country`) 
						VALUES (
								:form_id, 
								:record_id, 
								:payment_id, 
								:date_created, 
								:payment_date, 
								:payment_status, 
								:payment_fullname, 
								:payment_amount, 
								:payment_currency, 
								:payment_test_mode,
								:payment_merchant_type, 
								:status, 
								:billing_street, 
								:billing_city, 
								:billing_state, 
								:billing_zipcode, 
								:billing_country, 
								:same_shipping_address, 
								:shipping_street, 
								:shipping_city, 
								:shipping_state, 
								:shipping_zipcode, 
								:shipping_country)";		
		
		$params = array();
		$params[':form_id'] 		  	= $form_id;
		$params[':record_id'] 			= $payment_record_id;
		$params[':payment_id'] 			= $payment_id;
		$params[':date_created'] 		= date("Y-m-d H:i:s");
		$params[':payment_date'] 		= date("Y-m-d H:i:s");
		$params[':payment_status'] 		= 'paid';
		$params[':payment_fullname']  	= $payment_fullname;
		$params[':payment_amount'] 	  	= $payment_amount;
		$params[':payment_currency']  	= $payment_currency;
		$params[':payment_test_mode'] 	= $payment_stripe_enable_test_mode;
		$params[':payment_merchant_type'] = 'stripe';
		$params[':status'] 			  	= 1;
		
		$params[':billing_street'] 		= $billing_street;
		$params[':billing_city']		= $billing_city;
		$params[':billing_state'] 		= $billing_state;
		$params[':billing_zipcode'] 	= $billing_zipcode;
		$params[':billing_country'] 	= $billing_country;
		
		$params[':same_shipping_address'] = 0;
		
		$params[':shipping_street'] 	= $shipping_street;
		$params[':shipping_city'] 		= $shipping_city;
		$params[':shipping_state'] 		= $shipping_state;
		$params[':shipping_zipcode'] 	= $shipping_zipcode;
		$params[':shipping_country'] 	= $shipping_country;

		mf_do_query($query,$params,$dbh);

		//process any delayed notifications
		mf_process_delayed_notifications($dbh,$form_id,$payment_record_id);

		//redirect to success page, which might be coming from the logic, the default success page or the custom redirect URL being set on form properties
		if(!empty($logic_success_enable) && (($logic_redirect_url = mf_get_logic_success_redirect_url($dbh,$form_id,$payment_record_id)) != '')){
			$final_redirect_url = $logic_redirect_url;
		}else if(!empty($form_redirect_enable) && !empty($form_redirect)){
			//parse redirect URL for any template variables first
			$final_redirect_url = mf_parse_template_variables($dbh,$form_id,$payment_record_id,$form_redirect);
		}else{			
			//default success page
			if(!empty($mfsid)){
				$final_redirect_url = $mf_settings['base_url'].'view.php?id='.$form_id.'&done=1&mfsid='.$mfsid; 
			}else{
				$final_redirect_url = $mf_settings['base_url'].'view.php?id='.$form_id.'&done=1'; 
			}
		}
		$payment_result_status = "success";
	}catch(PaymentProcessingException $e){
		$payment_result_status = "processing";
	}catch(Exception $e){
		$payment_result_status = "error";
		$payment_result_error_message = "Exception: ".$e->getMessage();
	}catch(Throwable $e){
		$payment_result_status = "error";
		$payment_result_error_message = "Error: ".$e->getMessage()." in ".basename($e->getFile())." on line ".$e->getLine(); 
	}finally{

		//display payment result page
		if($payment_result_status == "success"){
			display_payment_result_page([
				'status' => 'success',
				'redirect_url' => $final_redirect_url
			]);
		}else if($payment_result_status == "processing"){
			display_payment_result_page([
				'status' => 'processing'
			]);
		}else if($payment_result_status == "error"){
			display_payment_result_page([
				'status' => 'error',
				'message' => $payment_result_error_message
			]);
		}

	}

	//function to display different success / error page based on configurations
	function display_payment_result_page($config = []){
		$default_config = [
			'status' => 'success',
			'message' => '',
			'redirect_url' => ''
		];

		$config = array_merge($default_config, $config);

		if($config['status'] == 'success'){
			//display success page
			$redirect_url = json_encode($config['redirect_url']);
			$page_html=<<<EOT
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Processing Payment...</title>
  <style>
    body {
      font-family: sans-serif;
      text-align: center;
      padding-top: 100px;
    }

    h2 {
      color: #333;
    }

    .progress-container {
      width: 80%;
      max-width: 400px;
      margin: 30px auto;
      background-color: #eee;
      border-radius: 20px;
      overflow: hidden;
      box-shadow: 0 0 10px rgba(0,0,0,0.05);
      position: relative;
    }

    .progress-bar {
      height: 22px;
      width: 0%;
      background-color: #3498db;
      color: #fff;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 14px;
      font-weight: bold;
      white-space: nowrap;
      transition: width 0.1s ease-in-out;
    }
  </style>
</head>
<body>

  <h2>Finalizing your payment...</h2>
  <p>Please don’t close this window.</p>

  <div class="progress-container">
    <div class="progress-bar" id="progressBar">0%</div>
  </div>

  <script>
    const redirectUrl = {$redirect_url};
    const progressBar = document.getElementById('progressBar');

    let progress = 0;
    const interval = setInterval(() => {
      progress++;
      progressBar.style.width = progress + '%';
      progressBar.textContent = progress + '%';

      if (progress >= 100) {
        clearInterval(interval);
        window.location.href = redirectUrl;
      }
    }, 10); 
  </script>

</body>
</html>
EOT;
		}else if($config['status'] == 'processing'){
			//display processing page
			$page_html=<<<EOT
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Payment Processing</title>
  <style>
    body {
      font-family: sans-serif;
      background-color: #f9f9f9;
      color: #333;
      text-align: center;
      padding: 100px 20px;
    }

    .card {
      max-width: 500px;
      margin: auto;
      background: #fff;
      padding: 40px;
      border-radius: 12px;
      box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
    }

    .loader {
      border: 6px solid #f3f3f3;
      border-top: 6px solid #3498db;
      border-radius: 50%;
      width: 50px;
      height: 50px;
      animation: spin 1s linear infinite;
      margin: 20px auto;
    }

    @keyframes spin {
      0% { transform: rotate(0deg); }
      100% { transform: rotate(360deg); }
    }

    h1 {
      font-size: 24px;
      margin-bottom: 10px;
    }

    p {
      font-size: 16px;
      color: #666;
      line-height: 1.6;
    }

    .note {
      margin-top: 20px;
      font-size: 14px;
      color: #999;
    }
  </style>
</head>
<body>
  <div class="card">
    <div class="loader"></div>
    <h1>Payment in Progress</h1>
    <p>
      <br>Thank you! Your bank transfer is being processed.<br>
      This may take 3–5 business days to complete.<br><br>
    </p>

    <p class="note">
    You’ll get an email once it’s done.<br>It’s safe to close this window.
    </p>
  </div>
</body>
</html>
EOT;
		}else if($config['status'] == 'error'){
			//display error page
			$error_message = htmlspecialchars($config['message']);
			$page_html=<<<EOT
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Payment Error</title>
  <style>
    body {
      font-family: 'Segoe UI', sans-serif;
      background-color: #f9f9f9;
      color: #b00020;
      text-align: center;
      padding: 100px 20px;
    }

    .card {
      max-width: 400px;
      margin: auto;
      background: #fff;
      padding: 30px;
      border-radius: 12px;
      border: 1px solid #ffcdd2;
      box-shadow: 0 2px 10px rgba(255, 0, 0, 0.05);
    }

    .icon {
      font-size: 48px;
      color: #b00020;
      margin-bottom: 20px;
    }

    h1 {
      font-size: 22px;
      margin-bottom: 10px;
    }

    p {
      font-size: 15px;
      color: #555;
    }

    .note {
      margin-top: 15px;
      font-size: 13px;
      color: #999;
    }

   
  </style>
</head>
<body>
  <div class="card">
    <div class="icon">⚠️</div>
    <h1>Payment Failed</h1>
    <p>Something went wrong while processing your payment.</p>
    <p style="font-style: italic">{$error_message}</p>
   
    <p class="note">If you keep seeing this error, please contact support.</p>
  </div>
</body>
</html>
EOT;
		}
		
		echo $page_html;
	}